package game;

import java.util.LinkedList;

public class Game {
	private LinkedList<Player> players;
	private LinkedList<Card> warStack;
	private CardDeck cards;
	private LinkedList<Card> fightingCards;
	private LinkedList<Player> fightingPlayers;
	private int battles;
	private int wars;
	private Player roundWinner;
	
	public Game(int playerCount, int deckCount) {
		players = new LinkedList<>();
		for(int i=0;i<playerCount;i++)
			players.add(new Player("player "+(i+1)));
		
		cards = new CardDeck();
		for(int i=0;i<deckCount;i++)
			cards.addNewDeck();
		
		warStack = new LinkedList<>();
		fightingCards = new LinkedList<>();
		fightingPlayers = new LinkedList<>();
	}
	
	public GameResults startGame() {
		roundWinner = null;
		battles=0;
		wars=0;
		giveOutCards();
		//game loop
		while(roundWinner==null) {
			battles++;
			fightingPlayers.clear();
			for(Player player: players)
				fightingPlayers.add(player);
			collectCards();
			Player winner = determineWinner();
			if(winner!=null) {
				claimCards(winner);
			}
			roundWinner = getRoundWinner();

			if(checkForDraw()) { //draw by rules
				//printStats();
				return new GameResults(wars, battles, true, false);
			}
			if(battles>=GameSettings.maxIterations)
				break;
		}
		//printStats();
		return new GameResults(wars, battles, false, (roundWinner==null));
	}
	
	private boolean checkForDraw()
	{
		for(Player player : players)
			if(player.getCardCount()>0)
				return false;
		return true;
	}
	
	private void printStats() {
		if(roundWinner!=null)
			System.out.println("Round has ended and was won by "+roundWinner.getName()+". Battles: "+battles+" Wars: "+wars);
		else if(battles==GameSettings.maxIterations)
			System.out.println("Round ended inconclusively (Infinite game). Battles: "+battles+" Wars: "+wars);
		else
			System.out.println("Round ended inconclusively (All players lost). Battles: "+battles+" Wars: "+wars);
	}
	
	private Player getRoundWinner() {
		Player winner = null;
		for(Player player : players)
			if(player.stillAlive)
				if(winner!=null)
					return null;
				else
					winner = player;
		return winner;
	}
	
	private void claimCards(Player winner) {
		winner.addCards(warStack);
		warStack.clear();
	}
	
	private void collectCards() {
		fightingCards.clear();
		for(Player player: players) {
			if(!player.isStillAlive()||!fightingPlayers.contains(player))
				continue;
			Card theCard = player.getCard();
			if(theCard==null) {
				player.setActive(false);
				continue;
			}
			fightingCards.add(theCard);
			warStack.add(theCard);
		}
	}
	
	private Player determineWinner() {
		if(fightingCards.size()==1)
			return fightingCards.getFirst().getOwner();
		if(fightingCards.size()==0)
			return null;
		LinkedList<Card> bestCards = new LinkedList<>();
		Rank bestRank = null;
		while(bestCards.isEmpty()) {
			if(bestRank==null)
				bestRank=Rank.UNDEFINED;
			else if(bestRank==Rank.UNDEFINED)
				bestRank=Rank.ACE;
			else if(bestRank==Rank.ACE)
				bestRank=Rank.KING;
			else if(bestRank==Rank.TWO)
				throw new UnsupportedOperationException("nie ma kart, czy co?");
			else
				bestRank = Rank.intToRank(bestRank.getValue()-1);
			for(Card theCard : fightingCards) {
				if(theCard.getCardRank()==bestRank)
					bestCards.add(theCard);
			}
		}
		if(bestCards.size()==1)
			return bestCards.getFirst().getOwner();
		fightingPlayers.clear();
		for(Card theCard: bestCards)
			fightingPlayers.add(theCard.getOwner());
		collectCards(); //hidden cards
		collectCards(); //next fighting cards
		wars++;
		return determineWinner();
	}
	
	private void giveOutCards() {
		int i=0;
		Card theCard;
		while((theCard=cards.getCard())!=null) {
			players.get(i).addCard(theCard);
			i++;
			if(i>=players.size())
				i=0;
		}
	}
}
